---
title: Testing
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import CodeBlock from "@theme/CodeBlock";
import testingOriginalTestFlutter from "!!raw-loader!/docs/cookbooks/testing_original_test_flutter.dart";
import testingOriginalTestDart from "!!raw-loader!/docs/cookbooks/testing_original_test_dart.dart";
import repositorySnippet from "!!raw-loader!/docs/cookbooks/testing_repository.dart";
import testFlutter from "!!raw-loader!/docs/cookbooks/testing_flutter.dart";
import testDart from "!!raw-loader!/docs/cookbooks/testing_dart.dart";
import testFull from "!!raw-loader!/docs/cookbooks/testing_full.dart";
import testOverrideInfo from "!!raw-loader!/docs/cookbooks/testing_override_info.dart";
import { trimSnippet } from "@site/src/components/CodeSnippet";

:::caution
<!---
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
-->
本页内容可能已经过时。  
今后会进行更新，但目前您可能需要参考侧边栏顶部的内容（介绍/要点/应用案例/......）。
:::

For any medium to large-scale applications, it is critical to test the application.

To successfully test our application, we will want the following things:

- No state should be preserved between `test`/`testWidgets`.  
  That means no global state in the application, or all global states should reset after each test.

- Being able to force our providers to have a specific state, either through
  mocking or by manipulating them until we reach the desired state.

Let's see one by one how [Riverpod] helps you with these.

## No state should be preserved between `test`/`testWidgets`.

Since providers are usually declared as global variables, you might worry about
that one.  
After all, global state makes testing very difficult, because it can require
lengthy `setUp`/`tearDown`.

But the reality is: While providers are declared as globals, the state of a provider
is **not** global.

Instead, it is stored in an object named [ProviderContainer], which you may have
seen if you looked at the dart-only examples.  
If you haven't, know that this [ProviderContainer] object is implicitly created
by [ProviderScope], the widget that enables [Riverpod] on our project.

Concretely what this means is, two `testWidgets` using providers do not share
any state.  
As such, there is no need for any `setUp`/`tearDown` at all.

But an example is better than lengthy explanations:

<Tabs
  defaultValue="testWidgets"
  values={[
    { label: 'testWidgets (Flutter)', value: 'testWidgets', },
    { label: 'test (Dart only)', value: 'test', },
  ]}
>
<TabItem value="testWidgets">

<CodeBlock>{trimSnippet(testingOriginalTestFlutter)}</CodeBlock>

</TabItem>
<TabItem value="test">

<CodeBlock>{trimSnippet(testingOriginalTestDart)}</CodeBlock>

</TabItem>
</Tabs>

As you can see, while `counterProvider` was declared as a global, no state was
shared between tests.  
As such, we do not have to worry about our tests potentially behaving differently
if executed in a different order, since they are running in complete isolation.

## Overriding the behavior of a provider during tests.

A common real-world application may have the following objects:

- It will have a `Repository` class, which provides a type-safe and simple API
  to perform HTTP requests.

- An object that manages the application state, and may use `Repository` to perform
  HTTP requests based on different factors.
  This may be a `ChangeNotifier`, `Bloc`, or even a provider.

Using [Riverpod], this may be represented as follows:

<CodeBlock>{trimSnippet(repositorySnippet)}</CodeBlock>

In this situation, when making a unit/widget test, we will typically want to
replace our `Repository` instance with a fake implementation that returns
a pre-defined response instead of making a real HTTP request.

We will then want our `todoListProvider` or equivalent to use the mocked implementation
of `Repository`.

To achieve this, we can use the `overrides` parameter of [ProviderScope]/[ProviderContainer]
to override the behavior of `repositoryProvider`:

<Tabs
  defaultValue="ProviderScope"
  values={[
    { label: 'ProviderScope (Flutter)', value: 'ProviderScope', },
    { label: 'ProviderContainer (Dart only)', value: 'ProviderContainer', },
  ]}
>
<TabItem value="ProviderScope">

<CodeBlock>{trimSnippet(testFlutter)}</CodeBlock>

</TabItem>
<TabItem value="ProviderContainer">

<CodeBlock>{trimSnippet(testDart)}</CodeBlock>

</TabItem>
</Tabs>

As you can see by the highlighted code, [ProviderScope]/[ProviderContainer]
allows replacing the implementation of a provider with a different behavior.

:::info
Some providers expose simplified ways to override their behavior.  
For example, [FutureProvider] allows overriding the provider with an `AsyncValue`:

<CodeBlock>{trimSnippet(testOverrideInfo)}</CodeBlock>

**Note**: As part of the 2.0.0 release, `overrideWithValue` methods are temporarily
removed. They will be added back in later versions.

:::

:::info
The syntax for overriding a provider with the `family` modifier is slightly different.

If you used a provider like this:

```dart
final response = ref.watch(myProvider('12345'));
```

You could override the provider as:

```dart
myProvider('12345').overrideWithValue(...));
```

:::

## Full widget test example

Wrapping up, here is the entire full code for our Flutter test.

<CodeBlock>{trimSnippet(testFull)}</CodeBlock>

[riverpod]: https://github.com/rrousselgit/riverpod
[providerscope]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ProviderScope-class.html
[providercontainer]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer-class.html
[futureprovider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/FutureProvider-class.html
[zone]: https://api.flutter.dev/flutter/dart-async/Zone-class.html
